package com.stylefeng.guns.core.util;

import java.io.IOException;
import java.net.URL;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HttpClient
{
  private static Logger logger = LoggerFactory.getLogger(HttpClient.class);
  private static final String DEFAULT_CHARSET = "UTF-8";
  private static SSLContext sslcontext;
  private static SSLConnectionSocketFactory sslsf;
  
  public static String doPost(String url, Map<String, String> params, int connectTimeout, int readTimeout)
    throws IOException
  {
    return doPost(url, params, "UTF-8", connectTimeout, readTimeout);
  }
  
  public static HttpResp doPost2(String url, Map<String, String> params, String charset, int connectTimeout, int readTimeout)
		    throws IOException
		  {
		    Map<String, String> headers = new HashMap();
		    headers.put("Content-type", "application/x-www-form-urlencoded;charset=" + charset);
		    return doPost2(url, headers, params, charset, connectTimeout, readTimeout);
		  }
  
  public static String doPost(String url, Map<String, String> params, String charset, int connectTimeout, int readTimeout)
    throws IOException
  {
    Map<String, String> headers = new HashMap();
    headers.put("Content-type", "application/x-www-form-urlencoded;charset=" + charset);
    return doPost(url, headers, params, charset, connectTimeout, readTimeout);
  }
  
  public static HttpResp doPost2(String url, Map<String, String> headers, Map<String, String> params, String charset,
			int connectTimeout, int readTimeout) throws IOException {
		HttpResp res = new HttpResp();
		URL targetUrl = new URL(url);
		HttpHost httpHost = new HttpHost(targetUrl.getHost(), targetUrl.getPort(), targetUrl.getProtocol());
		logger.info("host:" + targetUrl.getHost() + ",port:" + targetUrl.getPort() + ",protocol:"
				+ targetUrl.getProtocol() + ",path:" + targetUrl.getPath());
		CloseableHttpClient httpclient = getHttpClient(targetUrl);
		try {
			HttpPost httpPost = getHttpPost(targetUrl, headers, params, charset, connectTimeout, readTimeout);
			String resp = (String) httpclient.execute(httpHost, httpPost, new ResponseHandler() {
				public String handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
					int status = response.getStatusLine().getStatusCode();
					res.setStatus(status);
					HttpClient.logger.info("status:[{}]", new Object[] { Integer.valueOf(status) });
					if (status == 200) {
						return EntityUtils.toString(response.getEntity());
					}
					return "";
				}
			});
			res.setResMsg(resp);
			return res;
		} finally {
			httpclient.close();
		}
	}
  
  public static String doPost(String url, Map<String, String> headers, Map<String, String> params, String charset, int connectTimeout, int readTimeout)
    throws IOException
  {
    URL targetUrl = new URL(url);
    HttpHost httpHost = new HttpHost(targetUrl.getHost(), targetUrl.getPort(), targetUrl.getProtocol());
    logger.info("host:" + targetUrl.getHost() + ",port:" + targetUrl.getPort() + ",protocol:" + targetUrl.getProtocol() + ",path:" + targetUrl.getPath());
    
    CloseableHttpClient httpclient = getHttpClient(targetUrl);
    try
    {
      HttpPost httpPost = getHttpPost(targetUrl, headers, params, charset, 
        connectTimeout, readTimeout);
      
      String resp = (String)httpclient.execute(httpHost, httpPost, 
        new ResponseHandler()
        {
          public String handleResponse(HttpResponse response)
            throws ClientProtocolException, IOException
          {
            int status = response.getStatusLine().getStatusCode();
            
            HttpClient.logger.info("status:[{}]", new Object[] { Integer.valueOf(status) });
            if (status == 200) {
              return EntityUtils.toString(response.getEntity());
            }
            return "";
          }
        });
      return resp;
    }
    finally
    {
      httpclient.close();
    }
  }
  
  public static String doGet(String url, Map<String, String> params)
    throws IOException
  {
    return doGet(url, params, "UTF-8");
  }
  
  public static String doGet(String url, Map<String, String> params, String charset)
    throws IOException
  {
    Map<String, String> headers = new HashMap();
    headers.put("Content-type", "application/x-www-form-urlencoded;charset=" + charset);
    return doGet(url, headers, params, charset);
  }
  
  public static String doGet(String url, Map<String, String> headers, Map<String, String> params, String charset)
    throws IOException
  {
    URL targetUrl = new URL(url);
    CloseableHttpClient httpclient = getHttpClient(targetUrl);
    try
    {
      HttpGet httpGet = getHttpGet(url, headers, params, charset);
      
      String resp = (String)httpclient.execute(httpGet, 
        new ResponseHandler()
        {
          public String handleResponse(HttpResponse response)
            throws ClientProtocolException, IOException
          {
            int status = response.getStatusLine().getStatusCode();
            
            HttpClient.logger.info("status:[{}]", new Object[] { Integer.valueOf(status) });
            if (status == 200) {
              return EntityUtils.toString(response.getEntity());
            }
            return "";
          }
        });
      return resp;
    }
    finally
    {
      httpclient.close();
    }
  }
  
  private static HttpGet getHttpGet(String url, Map<String, String> headers, Map<String, String> params, String charset)
    throws IOException
  {
    URL targetUrl = HttpUtil.buildGetUrl(url, HttpUtil.buildQuery(params, charset));
    HttpGet httpGet = new HttpGet(targetUrl.toString());
    
    Iterator<Map.Entry<String, String>> iterator = headers.entrySet().iterator();
    while (iterator.hasNext())
    {
      Map.Entry<String, String> entry = (Map.Entry)iterator.next();
      httpGet.setHeader((String)entry.getKey(), (String)entry.getValue());
    }
    return httpGet;
  }
  
  private static HttpPost getHttpPost(URL targetUrl, Map<String, String> headers, Map<String, String> params, String charset, int connectTimeout, int readTimeout)
    throws IOException
  {
    HttpPost httpPost = new HttpPost(targetUrl.getPath());
    
    Iterator<Map.Entry<String, String>> iterator = headers.entrySet().iterator();
    while (iterator.hasNext())
    {
      Map.Entry<String, String> entry = (Map.Entry)iterator.next();
      httpPost.setHeader((String)entry.getKey(), (String)entry.getValue());
    }
    RequestConfig requestConfig = RequestConfig.custom()
      .setSocketTimeout(readTimeout)
      .setConnectTimeout(connectTimeout)
      .build();
    httpPost.setConfig(requestConfig);
    
    StringEntity entity = new StringEntity(HttpUtil.buildQuery(params, charset), charset);
    httpPost.setEntity(entity);
    
    return httpPost;
  }
  
  private static CloseableHttpClient getHttpClient(URL targetUrl) {
	  CloseableHttpClient httpClient = null;
	  try {
		    if ("https".equals(targetUrl.getProtocol())) {
		      httpClient = new SSLClient();
		    } else {
		    	 httpClient = HttpClients.createDefault();
		    }
	} catch (Exception e) {
		e.printStackTrace();
	}
	  return httpClient;
  }
  
  private static class DefaultTrustManager
    implements X509TrustManager
  {
    public X509Certificate[] getAcceptedIssuers()
    {
      return null;
    }
    
    public void checkClientTrusted(X509Certificate[] chain, String authType)
      throws CertificateException
    {}
    
    public void checkServerTrusted(X509Certificate[] chain, String authType)
      throws CertificateException
    {}
  }
  
  static
  {
    try
    {
      sslcontext = SSLContext.getInstance("TLS");
      sslcontext.init(new KeyManager[0], new TrustManager[] { new DefaultTrustManager() }, 
        new SecureRandom());
      

      sslsf = new SSLConnectionSocketFactory(
        sslcontext, 
        new String[] { "TLSv1" }, 
        null, 
        new HostnameVerifier()
        {
          public boolean verify(String hostname, SSLSession session)
          {
            return true;
          }
        });
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }
  }
}
